package com.yeyks.controller.activity;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.yeyks.account.dal.domain.AccountInfo;
import com.yeyks.annotation.NeedToken;
import com.yeyks.common.ajax.AjaxResponseBody;
import com.yeyks.common.base.Arguments;
import com.yeyks.common.constants.AccountType;
import com.yeyks.common.constants.OrderStatus;
import com.yeyks.common.exception.ServiceException;
import com.yeyks.common.param.PageParam;
import com.yeyks.common.param.activity.AddCouponPushUserParam;
import com.yeyks.common.param.activity.CouponPushParam;
import com.yeyks.common.utils.DateUtils;
import com.yeyks.common.utils.RedisUtil;
import com.yeyks.common.utils.apputil.rediskey.RedisKey;
import com.yeyks.commonReference.append.mongodb.entity.CouponPushMongoEntity;
import com.yeyks.commonReference.append.mongodb.service.CouponPushUserMongoService;
import com.yeyks.commonReference.service.order.OrderHeadService;
import com.yeyks.commonReference.service.other.CouponInfoService;
import com.yeyks.consumer.dal.domain.UserCouponInfo;
import com.yeyks.consumer.dal.domain.UserCouponPush;
import com.yeyks.consumer.dal.domain.UserInfo;
import com.yeyks.consumer.service.UserCouponPushService;
import com.yeyks.consumer.service.UserInfoService;
import com.yeyks.order.dal.domain.OrderHead;
import com.yeyks.other.dal.domain.CouponInfo;
import com.yeyks.web.AccountUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: dagny
 * @date: 2019/11/28 0028 11:40
 */
@Api(tags = "v3.8优惠券推送")
@RestController
@Slf4j
@RequestMapping(value = "/coupon/push")
public class CouponPushController {


    @Autowired
    private CouponPushUserMongoService couponPushUserMongoService;

    @Autowired
    private OrderHeadService orderHeadService;

    @Autowired
    private UserInfoService userInfoService;

    @Autowired
    private CouponInfoService couponInfoService;

    @Autowired
    private UserCouponPushService userCouponPushService;

    @Autowired
    private RedisUtil redisUtil;

    @NeedToken
    @ApiOperation("添加单个指定的用户")
    @PostMapping("/add/one")
    public AjaxResponseBody addUser(@RequestParam(value = "userId") String userId,
                                    @RequestParam(value = "phone") String phone) {
        AccountInfo loginUser = AccountUtils.getLoginUser();
        if (loginUser.getType() != AccountType.Administrator) {
            throw new ServiceException("没有权限操作");
        }
        AjaxResponseBody body = AjaxResponseBody.failed();
        CouponPushMongoEntity entity = new CouponPushMongoEntity();
        entity.setUserId(userId);
        entity.setPhone(phone);
        boolean flag = couponPushUserMongoService.save(entity);
        if (flag) {
            body = AjaxResponseBody.success();
        }
        return body;
    }

    @NeedToken
    @ApiOperation("添加符合条件的用户")
    @PostMapping("/add")
    public AjaxResponseBody addUser(@Validated AddCouponPushUserParam param) {
        AccountInfo loginUser = AccountUtils.getLoginUser();
        if (loginUser.getType() != AccountType.Administrator) {
            throw new ServiceException("没有权限操作");
        }
        AjaxResponseBody body = AjaxResponseBody.failed();
        if (Arguments.strIsNull(param.getType())) {
            throw new ServiceException("type：查询类型不能为空");
        }
        List<CouponPushMongoEntity> couponPushMongoEntityList = Lists.newArrayList();
        switch (param.getType()) {
            case "0":
                List<UserInfo> list = userInfoService.list(new QueryWrapper<UserInfo>().eq(UserInfo.IS_DEL, 1)
                        .eq(UserInfo.STATUS, 1));
                if (!CollectionUtils.isEmpty(list)) {
                    list.forEach(userInfo -> {
                        CouponPushMongoEntity entity = new CouponPushMongoEntity(String.valueOf(userInfo.getId()),
                                userInfo.getPhone());
                        couponPushMongoEntityList.add(entity);
                    });
                }
                list.clear();
                break;
            case "1":
                //时间戳转换
                if (param.getDissipate() == null || param.getDissipate() == 0) {
                    throw new ServiceException("最近消费时间不能为空");
                }
                String beforeTime = DateUtils.stampToYMDStr(param.getDissipate());
                List<OrderHead> orderHeadList = orderHeadService.list(new QueryWrapper<OrderHead>().gt(OrderHead.GMT_CREATE, beforeTime));
                if (!CollectionUtils.isEmpty(orderHeadList)) {
                    List<Integer> userIds = orderHeadList.stream().map(OrderHead::getUserId).distinct().collect(Collectors.toList());
                    list = selectByIds(userIds);
                    if (!CollectionUtils.isEmpty(list)) {
                        list.forEach(userInfo -> {
                            CouponPushMongoEntity entity = new CouponPushMongoEntity(String.valueOf(userInfo.getId()),
                                    userInfo.getPhone());
                            couponPushMongoEntityList.add(entity);
                        });
                    }
                    list.clear();
                }
                break;
            case "2":
                list = getMonetary(param.getDissipate(), param.getMonetary());
                if (!CollectionUtils.isEmpty(list)) {
                    list.forEach(userInfo -> {
                        CouponPushMongoEntity entity = new CouponPushMongoEntity(String.valueOf(userInfo.getId()),
                                userInfo.getPhone());
                        couponPushMongoEntityList.add(entity);
                    });
                }
                list.clear();
                break;
            case "3":
                list = getFrequency(param.getDissipate(), param.getFrequency());
                if (!CollectionUtils.isEmpty(list)) {
                    list.forEach(userInfo -> {
                        CouponPushMongoEntity entity = new CouponPushMongoEntity(String.valueOf(userInfo.getId()),
                                userInfo.getPhone());
                        couponPushMongoEntityList.add(entity);
                    });
                }
                list.clear();
                break;
            case "4":
                list = getUseCouponCount(param.getDissipate(), param.getUseCouponCount());
                if (!CollectionUtils.isEmpty(list)) {
                    list.forEach(userInfo -> {
                        CouponPushMongoEntity entity = new CouponPushMongoEntity(String.valueOf(userInfo.getId()),
                                userInfo.getPhone());
                        couponPushMongoEntityList.add(entity);
                    });
                }
                list.clear();
                break;
            case "5":
                //TODO 订单中城市ID
                log.info("订单中城市ID暂时未开发");
                break;
            default:
                throw new ServiceException("type：查询类型不存在");
        }
        //存入mongo
        boolean flag = couponPushUserMongoService.saveBatch(couponPushMongoEntityList);
        if (flag) {
            body = AjaxResponseBody.success();
            couponPushMongoEntityList.clear();
        }else{
            body = AjaxResponseBody.failed("插入数据为空, 请重新筛选！");
        }
        return body;
    }

    @NeedToken
    @ApiOperation("查询符合条件的用户")
    @PostMapping("/query")
    public AjaxResponseBody queryUser(@Validated PageParam pageParam) {

        AjaxResponseBody body = null;

        List<CouponPushMongoEntity> list = couponPushUserMongoService.queryByPage(pageParam);
        long count = couponPushUserMongoService.queryCount(pageParam);
        Map<String, Object> map = Maps.newHashMap();
        if (!CollectionUtils.isEmpty(list)) {
            map.put("list", list);
        } else {
            map.put("list", Lists.newArrayList());
        }
        map.put("count", count);
        body = AjaxResponseBody.success(map);
        return body;
    }

    @NeedToken
    @ApiOperation("清空符合条件的用户")
    @PostMapping("/clear")
    public AjaxResponseBody clearUser() {

        AjaxResponseBody body = AjaxResponseBody.failed();

        boolean flag = couponPushUserMongoService.clearCouponPush();
        if (flag) {
            body = AjaxResponseBody.success();
        }
        return body;
    }

    @NeedToken
    @ApiOperation("推送选中的用户")
    @PostMapping("/pushed")
    public AjaxResponseBody pushUser(@Validated CouponPushParam param) {

        AccountInfo loginUser = AccountUtils.getLoginUser();
        if (loginUser.getType() != AccountType.Administrator) {
            throw new ServiceException("没有权限操作");
        }
        AjaxResponseBody body = AjaxResponseBody.failed();

        if (StringUtils.isEmpty(param.getCouponIds())) {
            throw new ServiceException("优惠券Id不能空");
        }
        List<UserCouponInfo> userCouponInfoList = Lists.newArrayList();
        String[] split = param.getCouponIds().split(",");
        List<Integer> ids = Lists.newArrayList();
        for (String couponId : split) {
            ids.add(Integer.valueOf(couponId));
        }
        List<CouponInfo> list = couponInfoService.list(new QueryWrapper<CouponInfo>().in(CouponInfo.ID, ids)
                .ne(CouponInfo.STATUS, 3));

        //查询所有推送账户
        List<CouponPushMongoEntity> userList = couponPushUserMongoService.findAll();
        if (CollectionUtils.isEmpty(userList)) {
            throw new ServiceException("推送账户不能为空");
        }

        //验证优惠券数量和用户数
        if (CollectionUtils.isEmpty(list)) {
            throw new ServiceException("推送优惠券不能为空");
        }
        for (CouponInfo couponInfo : list) {
            if (couponInfo.getRemainCount() < userList.size()) {
                throw new ServiceException("优惠券名称为：【" + couponInfo.getTitle() + "】的剩余数量不足");
            }
        }
        List<Integer> couponIds = list.stream().map(CouponInfo::getId).collect(Collectors.toList());
        //添加推送信息
        UserCouponPush couponPush = new UserCouponPush();
        couponPush.setTitle(param.getTitle());
        couponPush.setPushStartTime(DateUtils.stampToYMDHMSDate(param.getPushStartTime()));
        couponPush.setPushEndTime(DateUtils.stampToYMDHMSDate(param.getPushEndTime()));
        List<String> collect = userList.stream()
                .map(CouponPushMongoEntity::getUserId).collect(Collectors.toList());
        if (collect.size() < 2000) {
            couponPush.setUserIdJson(collect.toString());
        } else {
            couponPush.setUserIdJson("具体查看Redis缓存");
        }

        couponPush.setCouponIdJson(JSON.toJSONString(couponIds));
        boolean save = userCouponPushService.save(couponPush);
        if (save) {
            String key = RedisKey.COUPON_PUSH_KEY_USER_ID + couponPush.getId();

            HashMap<String, Object> map = Maps.newHashMap();
            for(CouponPushMongoEntity user : userList){
                map.put(user.getUserId(), user.getPhone());
            }
            redisUtil.hset(key, map);
            body = AjaxResponseBody.success();
        }
        return body;
    }

    /**
     * 最近消费金额用户
     *
     * @param dissipate 时间戳
     * @param monetary  消费金额（分）
     * @return
     */
    private List<UserInfo> getMonetary(Long dissipate, String monetary) {

        //时间戳转换
        if (dissipate == null || dissipate == 0) {
            throw new ServiceException("最近消费时间不能为空");
        }
        String beforeTime = DateUtils.stampToYMDStr(dissipate);
        //金额区间
        if (Arguments.strIsNull(monetary)) {
            throw new ServiceException("最近消费金额不能为空!");
        }
        int startFee = 0;
        int endFee = 0;
        if (monetary.contains("-")) {
            String[] split = monetary.split("-");
            startFee = Integer.parseInt(split[0].trim());
            endFee = Integer.parseInt(split[1].trim());
            if(endFee == 0){
                endFee = -1;
            }
        } else {
            endFee = Integer.parseInt(monetary);
        }
        QueryWrapper<OrderHead> queryWrapper = new QueryWrapper<OrderHead>().gt(OrderHead.GMT_CREATE, beforeTime)
                .groupBy(OrderHead.USER_ID);
        if(endFee == -1){
            queryWrapper.having("sum(snapshot_total_fee) > {0}", startFee);
        }else{
            queryWrapper.having("sum(snapshot_total_fee) between {0} and {1}", startFee, endFee);
        }
        //得到结果的订单列表
        List<OrderHead> orderHeadList = orderHeadService.list(queryWrapper);

        return convertUserInfo(orderHeadList);
    }

    /**
     * 最近消费频率用户
     *
     * @param dissipate 时间戳
     * @param frequency 频率，单位次
     * @return
     */
    private List<UserInfo> getFrequency(Long dissipate, String frequency) {
        List<UserInfo> userInfoList = Lists.newArrayList();
        //时间戳转换
        if (dissipate == null || dissipate == 0) {
            throw new ServiceException("最近消费时间不能为空");
        }
        String beforeTime = DateUtils.stampToYMDStr(dissipate);
        if (Arguments.strIsNull(frequency)) {
            throw new ServiceException("最近消费频率不能为空");
        }
        int startCount = 0;
        int endCount = 0;
        if (frequency.contains("-")) {
            String[] split = frequency.split("-");
            startCount = Integer.valueOf(split[0].trim());
            endCount = Integer.valueOf(split[1].trim());
            if(endCount == 0){
                endCount = -1;
            }
        } else {
            endCount = Integer.valueOf(frequency.trim());
        }
        QueryWrapper<OrderHead> queryWrapper = new QueryWrapper<OrderHead>()
                .eq(OrderHead.STATUS, OrderStatus.postCheckOut)
                .gt(OrderHead.GMT_CREATE, beforeTime)
                .groupBy(OrderHead.USER_ID);
        if(endCount == -1){
            queryWrapper.having("count(order_no) > {0}", startCount);
        }else {
            queryWrapper.having("count(order_no) between {0} and {1}", startCount, endCount);
        }
        //得到结果的订单列表
        List<OrderHead> orderHeadList = orderHeadService.list(queryWrapper);


        return convertUserInfo(orderHeadList);
    }

    /**
     * 最近使用优惠券用户
     *
     * @param dissipate      最近时间
     * @param useCouponCount 优惠券数量
     * @return
     */
    private List<UserInfo> getUseCouponCount(Long dissipate, String useCouponCount) {
        if (Arguments.strIsNull(useCouponCount)) {
            throw new ServiceException("最近使用优惠券不能为空");
        }
        int startCouponCount = 0;
        int endCouponCount = 0;
        QueryWrapper<OrderHead> query = null;
        if (useCouponCount.contains("-")) {
            String[] split = useCouponCount.split("-");
            startCouponCount = Integer.parseInt(split[0].trim());
            endCouponCount = Integer.parseInt(split[1].trim());
            query = new QueryWrapper<OrderHead>()
                    .eq(OrderHead.STATUS, OrderStatus.postCheckOut)
                    .isNotNull(OrderHead.USER_COUPON_ID)
                    .ne(OrderHead.USER_COUPON_ID, 0)
                    .groupBy(OrderHead.USER_ID);
            if(endCouponCount == 0){
                query.having("count(user_coupon_id) > {0}", startCouponCount);
            }else {
                query.having("count(user_coupon_id) between {0} and {1}", startCouponCount, endCouponCount);
            }

        } else {
            endCouponCount = Integer.parseInt(useCouponCount.trim());
            query = new QueryWrapper<OrderHead>()
                    .eq(OrderHead.STATUS, OrderStatus.postCheckOut)
                    .groupBy(OrderHead.USER_ID)
                    .having("count(user_coupon_id) between {0} and {1}", startCouponCount, endCouponCount);
        }
        List<OrderHead> list = orderHeadService.list(query);

        return convertUserInfo(list);
    }

    /**
     * 最近预订城市
     *
     * @param dissipate 时间
     * @param cityId    城市ID
     * @return
     */
    private List<UserInfo> getCreateCity(Long dissipate, String cityId) {

        List<UserInfo> userInfoList = Lists.newArrayList();
        return null;
    }

    /**
     * 由订单列表筛选出账户列表
     * @param orderHeadList 订单列表
     * @return
     */
    private List<UserInfo> convertUserInfo(List<OrderHead> orderHeadList) {

        List<UserInfo> userInfoList = Lists.newArrayList();

        if (!CollectionUtils.isEmpty(orderHeadList)) {
            List<Integer> userIds = orderHeadList.stream().map(OrderHead::getUserId).distinct().collect(Collectors.toList());
            userInfoList = selectByIds(userIds);
        }
        return userInfoList;
    }

    /**
     * 根据用户
     *
     * @param userIds 用户Id集合
     * @return 返回用户集合
     */
    private List<UserInfo> selectByIds(List<Integer> userIds) {

        return userInfoService.list(new QueryWrapper<UserInfo>().eq(UserInfo.IS_DEL, 1)
                .eq(UserInfo.STATUS, 1).in(UserInfo.ID, userIds));
    }

}
